{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 6.希尔伯特矩阵 OLS 线性拟合"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[1.        , 0.5       , 0.33333333, 0.25      , 0.2       ,\n",
       "        0.16666667, 0.14285714, 0.125     , 0.11111111, 0.1       ],\n",
       "       [0.5       , 0.33333333, 0.25      , 0.2       , 0.16666667,\n",
       "        0.14285714, 0.125     , 0.11111111, 0.1       , 0.09090909],\n",
       "       [0.33333333, 0.25      , 0.2       , 0.16666667, 0.14285714,\n",
       "        0.125     , 0.11111111, 0.1       , 0.09090909, 0.08333333],\n",
       "       [0.25      , 0.2       , 0.16666667, 0.14285714, 0.125     ,\n",
       "        0.11111111, 0.1       , 0.09090909, 0.08333333, 0.07692308],\n",
       "       [0.2       , 0.16666667, 0.14285714, 0.125     , 0.11111111,\n",
       "        0.1       , 0.09090909, 0.08333333, 0.07692308, 0.07142857],\n",
       "       [0.16666667, 0.14285714, 0.125     , 0.11111111, 0.1       ,\n",
       "        0.09090909, 0.08333333, 0.07692308, 0.07142857, 0.06666667],\n",
       "       [0.14285714, 0.125     , 0.11111111, 0.1       , 0.09090909,\n",
       "        0.08333333, 0.07692308, 0.07142857, 0.06666667, 0.0625    ],\n",
       "       [0.125     , 0.11111111, 0.1       , 0.09090909, 0.08333333,\n",
       "        0.07692308, 0.07142857, 0.06666667, 0.0625    , 0.05882353],\n",
       "       [0.11111111, 0.1       , 0.09090909, 0.08333333, 0.07692308,\n",
       "        0.07142857, 0.06666667, 0.0625    , 0.05882353, 0.05555556],\n",
       "       [0.1       , 0.09090909, 0.08333333, 0.07692308, 0.07142857,\n",
       "        0.06666667, 0.0625    , 0.05882353, 0.05555556, 0.05263158]])"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from scipy.linalg import hilbert\n",
    "# Hilbert 矩阵是一个特殊的矩阵，其元素由以下公式定义：\n",
    "# \\[\n",
    "# H(i, j) = \\frac{1}{i + j - 1}\n",
    "# \\]\n",
    "# 它是一个对称正定矩阵，常用于数值分析中的测试问题，但由于其条件数较大，容易导致数值不稳定。x = hilbert(10) # 10x10 Hilbert matrix\n",
    "x = hilbert(10) # 10x10 Hilbert matrix\n",
    "x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "\n",
    "res = np.linalg.det(np.matrix(x).T * np.matrix(x))\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在 NumPy 中，`linalg` 是线性代数模块（`numpy.linalg`），它提供了许多用于线性代数计算的函数，例如矩阵的求解、特征值分解、矩阵的行列式计算等。\n",
    "\n",
    "---\n",
    "\n",
    "### 代码中的 `np.linalg.det`\n",
    "在你的代码中：\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "np.float64(-7.933946394895335e-92)"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.linalg.det(np.matrix(x).T * np.matrix(x))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- **`np.linalg.det`**：\n",
    "  - 用于计算矩阵的行列式（determinant）。\n",
    "  - 行列式是一个标量值，用于描述矩阵的一些特性，例如是否可逆。\n",
    "  - 如果行列式为 0，矩阵是奇异的（不可逆）；如果行列式不为 0，矩阵是可逆的。\n",
    "\n",
    "---\n",
    "\n",
    "### 代码解析\n",
    "1. **`np.matrix(x)`**：\n",
    "   - 将 `x` 转换为 NumPy 矩阵对象。\n",
    "   - 矩阵对象是 NumPy 中的一种特殊类型，专门用于矩阵运算。\n",
    "\n",
    "2. **`.T`**：\n",
    "   - 表示矩阵的转置操作。\n",
    "   - 将矩阵的行和列互换。\n",
    "\n",
    "3. **`np.matrix(x).T * np.matrix(x)`**：\n",
    "   - 计算矩阵 `x` 的转置与自身的乘积。\n",
    "   - 结果是一个对称矩阵，通常用于线性代数中的正规方程或特征值分解。\n",
    "\n",
    "4. **`np.linalg.det`**：\n",
    "   - 计算上述矩阵的行列式。\n",
    "\n",
    "---\n",
    "\n",
    "### 示例\n",
    "以下是一个完整的示例：\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "import numpy as np\n",
    "\n",
    "#### 定义矩阵 x\n",
    "x = np.array([[1, 2], [3, 4]])\n",
    "\n",
    "#### 转换为矩阵对象\n",
    "matrix_x = np.matrix(x)\n",
    "\n",
    "#### 计算转置与自身的乘积\n",
    "product = matrix_x.T * matrix_x\n",
    "\n",
    "#### 计算行列式\n",
    "determinant = np.linalg.det(product)\n",
    "\n",
    "print(\"矩阵 x:\")\n",
    "print(matrix_x)\n",
    "print(\"转置与自身的乘积:\")\n",
    "print(product)\n",
    "print(\"行列式:\")\n",
    "print(determinant)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "\n",
    "输出：\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": ""
    }
   },
   "outputs": [],
   "source": [
    "矩阵 x:\n",
    "[[1 2]\n",
    " [3 4]]\n",
    "转置与自身的乘积:\n",
    "[[10 14]\n",
    " [14 20]]\n",
    "行列式:\n",
    "4.0"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "\n",
    "---\n",
    "\n",
    "### 总结\n",
    "- **`np.linalg.det`**：计算矩阵的行列式。\n",
    "- **作用**：行列式可以用于判断矩阵是否可逆，或者用于线性代数中的其他计算。\n",
    "- **代码中的操作**：\n",
    "  - 计算矩阵 `x` 的转置与自身的乘积。\n",
    "  - 然后计算该乘积矩阵的行列式。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>x1</th>\n",
       "      <th>x2</th>\n",
       "      <th>x3</th>\n",
       "      <th>x4</th>\n",
       "      <th>x5</th>\n",
       "      <th>x6</th>\n",
       "      <th>x7</th>\n",
       "      <th>x8</th>\n",
       "      <th>x9</th>\n",
       "      <th>x10</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>x1</th>\n",
       "      <td>1.000000</td>\n",
       "      <td>0.985344</td>\n",
       "      <td>0.965392</td>\n",
       "      <td>0.948277</td>\n",
       "      <td>0.934230</td>\n",
       "      <td>0.922665</td>\n",
       "      <td>0.913025</td>\n",
       "      <td>0.904883</td>\n",
       "      <td>0.897921</td>\n",
       "      <td>0.891902</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>x2</th>\n",
       "      <td>0.985344</td>\n",
       "      <td>1.000000</td>\n",
       "      <td>0.995632</td>\n",
       "      <td>0.988183</td>\n",
       "      <td>0.980720</td>\n",
       "      <td>0.973927</td>\n",
       "      <td>0.967905</td>\n",
       "      <td>0.962598</td>\n",
       "      <td>0.957918</td>\n",
       "      <td>0.953774</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>x3</th>\n",
       "      <td>0.965392</td>\n",
       "      <td>0.995632</td>\n",
       "      <td>1.000000</td>\n",
       "      <td>0.998160</td>\n",
       "      <td>0.994616</td>\n",
       "      <td>0.990719</td>\n",
       "      <td>0.986928</td>\n",
       "      <td>0.983393</td>\n",
       "      <td>0.980155</td>\n",
       "      <td>0.977207</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>x4</th>\n",
       "      <td>0.948277</td>\n",
       "      <td>0.988183</td>\n",
       "      <td>0.998160</td>\n",
       "      <td>1.000000</td>\n",
       "      <td>0.999065</td>\n",
       "      <td>0.997120</td>\n",
       "      <td>0.994845</td>\n",
       "      <td>0.992525</td>\n",
       "      <td>0.990281</td>\n",
       "      <td>0.988163</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>x5</th>\n",
       "      <td>0.934230</td>\n",
       "      <td>0.980720</td>\n",
       "      <td>0.994616</td>\n",
       "      <td>0.999065</td>\n",
       "      <td>1.000000</td>\n",
       "      <td>0.999465</td>\n",
       "      <td>0.998294</td>\n",
       "      <td>0.996860</td>\n",
       "      <td>0.995346</td>\n",
       "      <td>0.993839</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>x6</th>\n",
       "      <td>0.922665</td>\n",
       "      <td>0.973927</td>\n",
       "      <td>0.990719</td>\n",
       "      <td>0.997120</td>\n",
       "      <td>0.999465</td>\n",
       "      <td>1.000000</td>\n",
       "      <td>0.999669</td>\n",
       "      <td>0.998914</td>\n",
       "      <td>0.997959</td>\n",
       "      <td>0.996922</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>x7</th>\n",
       "      <td>0.913025</td>\n",
       "      <td>0.967905</td>\n",
       "      <td>0.986928</td>\n",
       "      <td>0.994845</td>\n",
       "      <td>0.998294</td>\n",
       "      <td>0.999669</td>\n",
       "      <td>1.000000</td>\n",
       "      <td>0.999782</td>\n",
       "      <td>0.999271</td>\n",
       "      <td>0.998608</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>x8</th>\n",
       "      <td>0.904883</td>\n",
       "      <td>0.962598</td>\n",
       "      <td>0.983393</td>\n",
       "      <td>0.992525</td>\n",
       "      <td>0.996860</td>\n",
       "      <td>0.998914</td>\n",
       "      <td>0.999782</td>\n",
       "      <td>1.000000</td>\n",
       "      <td>0.999850</td>\n",
       "      <td>0.999491</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>x9</th>\n",
       "      <td>0.897921</td>\n",
       "      <td>0.957918</td>\n",
       "      <td>0.980155</td>\n",
       "      <td>0.990281</td>\n",
       "      <td>0.995346</td>\n",
       "      <td>0.997959</td>\n",
       "      <td>0.999271</td>\n",
       "      <td>0.999850</td>\n",
       "      <td>1.000000</td>\n",
       "      <td>0.999893</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>x10</th>\n",
       "      <td>0.891902</td>\n",
       "      <td>0.953774</td>\n",
       "      <td>0.977207</td>\n",
       "      <td>0.988163</td>\n",
       "      <td>0.993839</td>\n",
       "      <td>0.996922</td>\n",
       "      <td>0.998608</td>\n",
       "      <td>0.999491</td>\n",
       "      <td>0.999893</td>\n",
       "      <td>1.000000</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "           x1        x2        x3        x4        x5        x6        x7  \\\n",
       "x1   1.000000  0.985344  0.965392  0.948277  0.934230  0.922665  0.913025   \n",
       "x2   0.985344  1.000000  0.995632  0.988183  0.980720  0.973927  0.967905   \n",
       "x3   0.965392  0.995632  1.000000  0.998160  0.994616  0.990719  0.986928   \n",
       "x4   0.948277  0.988183  0.998160  1.000000  0.999065  0.997120  0.994845   \n",
       "x5   0.934230  0.980720  0.994616  0.999065  1.000000  0.999465  0.998294   \n",
       "x6   0.922665  0.973927  0.990719  0.997120  0.999465  1.000000  0.999669   \n",
       "x7   0.913025  0.967905  0.986928  0.994845  0.998294  0.999669  1.000000   \n",
       "x8   0.904883  0.962598  0.983393  0.992525  0.996860  0.998914  0.999782   \n",
       "x9   0.897921  0.957918  0.980155  0.990281  0.995346  0.997959  0.999271   \n",
       "x10  0.891902  0.953774  0.977207  0.988163  0.993839  0.996922  0.998608   \n",
       "\n",
       "           x8        x9       x10  \n",
       "x1   0.904883  0.897921  0.891902  \n",
       "x2   0.962598  0.957918  0.953774  \n",
       "x3   0.983393  0.980155  0.977207  \n",
       "x4   0.992525  0.990281  0.988163  \n",
       "x5   0.996860  0.995346  0.993839  \n",
       "x6   0.998914  0.997959  0.996922  \n",
       "x7   0.999782  0.999271  0.998608  \n",
       "x8   1.000000  0.999850  0.999491  \n",
       "x9   0.999850  1.000000  0.999893  \n",
       "x10  0.999491  0.999893  1.000000  "
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import pandas as pd\n",
    "\n",
    "pd.DataFrame(x, columns=[\"x%d\" % i for i in range(1, 11)]).corr()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在 Pandas 中，`.corr()` 方法用于计算 **列与列之间的相关系数**，即衡量两个变量之间的线性相关性。\n",
    "\n",
    "---\n",
    "\n",
    "### 1. **`.corr()` 的作用**\n",
    "- **功能**：计算数据框或序列中数值列之间的 **皮尔逊相关系数**（默认）。\n",
    "- **返回值**：\n",
    "  - 如果在 `DataFrame` 上调用，返回一个相关系数矩阵（`DataFrame`）。\n",
    "  - 如果在 `Series` 上调用，返回与另一个序列的相关系数（`float`）。\n",
    "\n",
    "---\n",
    "\n",
    "### 2. **相关系数的范围**\n",
    "- 相关系数的值范围是 **-1 到 1**：\n",
    "  - **1**：完全正相关（两个变量呈完全线性正相关）。\n",
    "  - **0**：无相关（两个变量之间没有线性关系）。\n",
    "  - **-1**：完全负相关（两个变量呈完全线性负相关）。\n",
    "\n",
    "---\n",
    "\n",
    "### 3. **语法**\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "DataFrame.corr(method='pearson', min_periods=1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "\n",
    "#### 参数：\n",
    "- **`method`**：\n",
    "  - `'pearson'`（默认）：皮尔逊相关系数，衡量线性相关性。\n",
    "  - `'kendall'`：肯德尔相关系数，衡量排序相关性。\n",
    "  - `'spearman'`：斯皮尔曼相关系数，衡量排序相关性。\n",
    "- **`min_periods`**：\n",
    "  - 计算相关系数所需的最小非缺失值数量。如果不足，则返回 `NaN`。\n",
    "\n",
    "---\n",
    "\n",
    "### 4. **示例**\n",
    "\n",
    "#### 示例 1：计算 `DataFrame` 的相关系数矩阵\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "\n",
    "# 创建一个 DataFrame\n",
    "data = {\n",
    "    'A': [1, 2, 3, 4, 5],\n",
    "    'B': [5, 4, 3, 2, 1],\n",
    "    'C': [2, 3, 4, 5, 6]\n",
    "}\n",
    "df = pd.DataFrame(data)\n",
    "\n",
    "# 计算相关系数矩阵\n",
    "correlation_matrix = df.corr()\n",
    "print(correlation_matrix)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "\n",
    "输出：\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": ""
    }
   },
   "outputs": [],
   "source": [
    "          A         B         C\n",
    "A  1.000000 -1.000000  1.000000\n",
    "B -1.000000  1.000000 -1.000000\n",
    "C  1.000000 -1.000000  1.000000"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "\n",
    "解释：\n",
    "- `A` 和 `B` 完全负相关（相关系数为 -1）。\n",
    "- `A` 和 `C` 完全正相关（相关系数为 1）。\n",
    "\n",
    "---\n",
    "\n",
    "#### 示例 2：计算两个 `Series` 的相关系数\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "\n",
    "# 创建两个 Series\n",
    "s1 = pd.Series([1, 2, 3, 4, 5])\n",
    "s2 = pd.Series([5, 4, 3, 2, 1])\n",
    "\n",
    "# 计算相关系数\n",
    "correlation = s1.corr(s2)\n",
    "print(correlation)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "\n",
    "输出：\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": ""
    }
   },
   "outputs": [],
   "source": [
    "-1.0"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "\n",
    "解释：\n",
    "- `s1` 和 `s2` 完全负相关。\n",
    "\n",
    "---\n",
    "\n",
    "#### 示例 3：使用不同的相关系数方法\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "correlation_kendall = df.corr(method='kendall')\n",
    "correlation_spearman = df.corr(method='spearman')\n",
    "\n",
    "print(\"Kendall correlation:\")\n",
    "print(correlation_kendall)\n",
    "\n",
    "print(\"Spearman correlation:\")\n",
    "print(correlation_spearman)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "\n",
    "---\n",
    "\n",
    "### 5. **应用场景**\n",
    "- **特征选择**：在机器学习中，使用 `.corr()` 找出高度相关的特征，避免多重共线性。\n",
    "- **数据分析**：分析变量之间的关系，判断是否存在线性相关性。\n",
    "- **可视化**：结合热力图（heatmap）展示相关系数矩阵。\n",
    "\n",
    "---\n",
    "\n",
    "### 总结\n",
    "- `.corr()` 是 Pandas 中用于计算相关系数的常用方法。\n",
    "- 默认计算 **皮尔逊相关系数**，也支持其他方法（如肯德尔、斯皮尔曼）。\n",
    "- 返回值可以是相关系数矩阵（`DataFrame`）或单个相关系数（`float`）。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[1.         0.5        0.33333333 0.25       0.2        0.16666667\n",
      "  0.14285714 0.125      0.11111111 0.1       ]\n",
      " [0.5        0.33333333 0.25       0.2        0.16666667 0.14285714\n",
      "  0.125      0.11111111 0.1        0.09090909]\n",
      " [0.33333333 0.25       0.2        0.16666667 0.14285714 0.125\n",
      "  0.11111111 0.1        0.09090909 0.08333333]\n",
      " [0.25       0.2        0.16666667 0.14285714 0.125      0.11111111\n",
      "  0.1        0.09090909 0.08333333 0.07692308]\n",
      " [0.2        0.16666667 0.14285714 0.125      0.11111111 0.1\n",
      "  0.09090909 0.08333333 0.07692308 0.07142857]\n",
      " [0.16666667 0.14285714 0.125      0.11111111 0.1        0.09090909\n",
      "  0.08333333 0.07692308 0.07142857 0.06666667]\n",
      " [0.14285714 0.125      0.11111111 0.1        0.09090909 0.08333333\n",
      "  0.07692308 0.07142857 0.06666667 0.0625    ]\n",
      " [0.125      0.11111111 0.1        0.09090909 0.08333333 0.07692308\n",
      "  0.07142857 0.06666667 0.0625     0.05882353]\n",
      " [0.11111111 0.1        0.09090909 0.08333333 0.07692308 0.07142857\n",
      "  0.06666667 0.0625     0.05882353 0.05555556]\n",
      " [0.1        0.09090909 0.08333333 0.07692308 0.07142857 0.06666667\n",
      "  0.0625     0.05882353 0.05555556 0.05263158]]\n",
      "[[14.14761905]\n",
      " [10.1232684 ]\n",
      " [ 8.12233045]\n",
      " [ 6.8529637 ]\n",
      " [ 5.95634643]\n",
      " [ 5.28188478]\n",
      " [ 4.75274309]\n",
      " [ 4.32480306]\n",
      " [ 3.97061256]\n",
      " [ 3.67205737]]\n",
      "实际参数 w:  [3 7 6 9 2 3 5 6 3 7]\n",
      "实际函数值 y:  [14.14761905 10.1232684   8.12233045  6.8529637   5.95634643  5.28188478\n",
      "  4.75274309  4.32480306  3.97061256  3.67205737]\n"
     ]
    }
   ],
   "source": [
    "from scipy.optimize import leastsq\n",
    "\n",
    "x = hilbert(10)  # 生成 10x10 的希尔伯特矩阵\n",
    "np.random.seed(10)  # 随机数种子能保证每次生成的随机数一致\n",
    "w = np.random.randint(2, 10, 10)  # 随机生成 w 系数\n",
    "y_temp = np.matrix(x) * np.matrix(w).T  # 计算 y 值\n",
    "print(y_temp)  # 打印 y_temp 矩阵\n",
    "y = np.array(y_temp.T)[0]  # 将 y 值转换成 1 维行向量\n",
    "\n",
    "print(\"实际参数 w: \", w)\n",
    "print(\"实际函数值 y: \", y)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "以下是对代码的详细解释：\n",
    "\n",
    "---\n",
    "\n",
    "### 代码功能\n",
    "这段代码的功能是：\n",
    "1. 生成一个 **希尔伯特矩阵**（Hilbert Matrix）。\n",
    "2. 随机生成一个系数向量 `w`。\n",
    "3. 使用矩阵乘法计算目标值 `y`，模拟一个线性模型的输出。\n",
    "4. 打印实际的参数 `w` 和计算得到的目标值 `y`。\n",
    "\n",
    "---\n",
    "\n",
    "### 代码逐行解析\n",
    "\n",
    "#### 1. **`from scipy.optimize import leastsq`**\n",
    "- 从 `scipy.optimize` 模块中导入 `leastsq` 函数。\n",
    "- **`leastsq`** 是用于最小二乘优化的函数，通常用于拟合模型参数。\n",
    "- 在这段代码中，`leastsq` 尚未被使用。\n",
    "\n",
    "---\n",
    "\n",
    "#### 2. **`x = hilbert(10)`**\n",
    "- **`hilbert(10)`**：\n",
    "  - 来自 `scipy.linalg` 模块，用于生成一个 `10x10` 的 **希尔伯特矩阵**。\n",
    "  - 希尔伯特矩阵是一个特殊的矩阵，其元素由公式 `H[i, j] = 1 / (i + j - 1)` 定义。\n",
    "  - 例如，`hilbert(3)` 的结果是：\n",
    "    ```\n",
    "    [[1.         0.5        0.33333333]\n",
    "     [0.5        0.33333333 0.25      ]\n",
    "     [0.33333333 0.25       0.2       ]]\n",
    "    ```\n",
    "  - 希尔伯特矩阵在数值计算中常用于测试，因为它是一个病态矩阵（条件数非常大）。\n",
    "\n",
    "---\n",
    "\n",
    "#### 3. **`np.random.seed(10)`**\n",
    "- 设置随机数种子为 `10`。\n",
    "- **作用**：\n",
    "  - 保证每次运行代码时生成的随机数序列相同，便于结果复现。\n",
    "\n",
    "---\n",
    "\n",
    "#### 4. **`w = np.random.randint(2, 10, 10)`**\n",
    "- 使用 `np.random.randint` 生成一个长度为 `10` 的随机整数向量 `w`。\n",
    "- 参数：\n",
    "  - `2`：随机整数的最小值（包含）。\n",
    "  - `10`：随机整数的最大值（不包含）。\n",
    "  - `10`：生成的整数个数。\n",
    "- 例如，可能生成的 `w` 是：\n",
    "  ```\n",
    "  [9 4 5 2 9 5 9 3 7 3]\n",
    "  ```\n",
    "\n",
    "---\n",
    "\n",
    "#### 5. **`y_temp = np.matrix(x) * np.matrix(w).T`**\n",
    "- 将 `x` 和 `w` 转换为矩阵对象，并计算矩阵乘法。\n",
    "- **操作**：\n",
    "  - `np.matrix(x)`：将希尔伯特矩阵 `x` 转换为矩阵对象。\n",
    "  - `np.matrix(w).T`：将向量 `w` 转换为列向量（`10x1` 矩阵）。\n",
    "  - `np.matrix(x) * np.matrix(w).T`：计算矩阵乘法，结果是一个 `10x1` 矩阵。\n",
    "- 结果 `y_temp` 是一个列向量，表示线性模型的输出。\n",
    "\n",
    "---\n",
    "\n",
    "#### 6. **`y = np.array(y_temp.T)[0]`**\n",
    "- 将 `y_temp` 转换为一维数组：\n",
    "  - `y_temp.T`：将列向量转置为行向量。\n",
    "  - `np.array(y_temp.T)`：将矩阵对象转换为 NumPy 数组。\n",
    "  - `[0]`：提取数组的第一行，得到一维数组。\n",
    "- 结果 `y` 是一个一维数组，表示目标值。\n",
    "\n",
    "---\n",
    "\n",
    "#### 7. **打印实际参数和目标值**\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(\"实际参数 w: \", w)\n",
    "print(\"实际函数值 y: \", y)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 打印随机生成的参数向量 `w` 和计算得到的目标值 `y`。\n",
    "\n",
    "---\n",
    "\n",
    "### 示例输出\n",
    "假设随机生成的 `w` 是 `[9, 4, 5, 2, 9, 5, 9, 3, 7, 3]`，则可能的输出为：\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": ""
    }
   },
   "outputs": [],
   "source": [
    "实际参数 w:  [9 4 5 2 9 5 9 3 7 3]\n",
    "实际函数值 y:  [2.92896825 1.86396825 1.41796825 1.14296825 0.95896825 0.82396825\n",
    " 0.71896825 0.63396825 0.56396825 0.50396825]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "\n",
    "---\n",
    "\n",
    "### 代码的作用总结\n",
    "1. **生成数据**：\n",
    "   - 使用希尔伯特矩阵 `x` 和随机系数向量 `w` 构造一个线性模型。\n",
    "   - 计算目标值 `y`，模拟线性模型的输出。\n",
    "\n",
    "2. **用途**：\n",
    "   - 这段代码通常用于测试线性模型的拟合能力。\n",
    "   - 后续可以使用 `leastsq` 或其他优化方法拟合参数 `w`，验证模型的性能。\n",
    "\n",
    "---\n",
    "\n",
    "### 希尔伯特矩阵的特点\n",
    "- 希尔伯特矩阵是一个病态矩阵，数值计算中容易引发不稳定性。\n",
    "- 这使得它成为测试数值算法（如线性回归、最小二乘法）的经典工具。---\n",
    "\n",
    "### 代码的作用总结\n",
    "1. **生成数据**：\n",
    "   - 使用希尔伯特矩阵 `x` 和随机系数向量 `w` 构造一个线性模型。\n",
    "   - 计算目标值 `y`，模拟线性模型的输出。\n",
    "\n",
    "2. **用途**：\n",
    "   - 这段代码通常用于测试线性模型的拟合能力。\n",
    "   - 后续可以使用 `leastsq` 或其他优化方法拟合参数 `w`，验证模型的性能。\n",
    "\n",
    "---\n",
    "\n",
    "### 希尔伯特矩阵的特点\n",
    "- 希尔伯特矩阵是一个病态矩阵，数值计算中容易引发不稳定性。\n",
    "- 这使得它成为测试数值算法（如线性回归、最小二乘法）的经典工具。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "拟合参数 w:  [ 3.00443349  6.80319769  8.07953155  0.44812657 17.07312717 -5.86293074\n",
      "  3.83274472 -0.05022415 17.17035927  0.49832937]\n"
     ]
    }
   ],
   "source": [
    "func = lambda p, x: np.dot(x, p)  # 函数公式\n",
    "err_func = lambda p, x, y: func(p, x) - y  # 残差函数\n",
    "p_init = np.random.randint(1, 2, 10)  # 全部参数初始化为 1\n",
    "\n",
    "parameters = leastsq(err_func, p_init, args=(x, y))  # 最小二乘法求解\n",
    "print(\"拟合参数 w: \", parameters[0])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "以下是对代码的详细解释：\n",
    "\n",
    "---\n",
    "\n",
    "### 代码功能\n",
    "这段代码的功能是：\n",
    "1. 定义一个线性模型 `func` 和对应的残差函数 `err_func`。\n",
    "2. 使用最小二乘法（`leastsq`）拟合模型参数 `p`，使得模型的预测值与目标值 `y` 的误差最小。\n",
    "3. 输出拟合得到的参数 `w`。\n",
    "\n",
    "---\n",
    "\n",
    "### 代码逐行解析\n",
    "\n",
    "#### 1. **`func = lambda p, x: np.dot(x, p)`**\n",
    "- 定义了一个匿名函数 `func`，表示线性模型的公式。\n",
    "- 参数：\n",
    "  - `p`：模型的参数向量（即待拟合的参数）。\n",
    "  - `x`：输入特征矩阵。\n",
    "- **`np.dot(x, p)`**：\n",
    "  - 计算矩阵 `x` 和向量 `p` 的点积，表示线性模型的预测值。\n",
    "  - 假设 `x` 是一个 `10x10` 的矩阵，`p` 是一个长度为 `10` 的向量，则结果是一个长度为 `10` 的向量。\n",
    "\n",
    "---\n",
    "\n",
    "#### 2. **`err_func = lambda p, x, y: func(p, x) - y`**\n",
    "- 定义了一个匿名函数 `err_func`，表示残差函数。\n",
    "- 参数：\n",
    "  - `p`：模型的参数向量。\n",
    "  - `x`：输入特征矩阵。\n",
    "  - `y`：目标值向量。\n",
    "- **`func(p, x) - y`**：\n",
    "  - 计算模型的预测值 `func(p, x)` 与目标值 `y` 之间的差值（残差）。\n",
    "  - 残差是一个向量，表示每个样本的预测值与真实值之间的误差。\n",
    "\n",
    "---\n",
    "\n",
    "#### 3. **`p_init = np.random.randint(1, 2, 10)`**\n",
    "- 使用 `np.random.randint` 初始化参数向量 `p`。\n",
    "- 参数：\n",
    "  - `1`：随机整数的最小值（包含）。\n",
    "  - `2`：随机整数的最大值（不包含）。\n",
    "  - `10`：生成的整数个数。\n",
    "- **结果**：\n",
    "  - 由于范围是 `[1, 2)`，生成的所有值都为 `1`。\n",
    "  - `p_init` 是一个长度为 `10` 的向量，初始值为 `[1, 1, 1, ..., 1]`。\n",
    "\n",
    "---\n",
    "\n",
    "#### 4. **`parameters = leastsq(err_func, p_init, args=(x, y))`**\n",
    "- 使用 `leastsq` 函数进行最小二乘法优化，拟合模型参数。\n",
    "- 参数：\n",
    "  - `err_func`：残差函数，`leastsq` 会尝试最小化该函数的值。\n",
    "  - `p_init`：参数的初始值。\n",
    "  - `args=(x, y)`：传递给 `err_func` 的额外参数，分别是输入特征矩阵 `x` 和目标值向量 `y`。\n",
    "- **`leastsq` 的作用**：\n",
    "  - 通过迭代优化，找到参数向量 `p`，使得残差函数 `err_func(p, x, y)` 的值最小。\n",
    "  - 返回值：\n",
    "    - `parameters[0]`：拟合得到的参数向量。\n",
    "    - 其他信息（如优化状态）存储在 `parameters[1]` 中。\n",
    "\n",
    "---\n",
    "\n",
    "#### 5. **`print(\"拟合参数 w: \", parameters[0])`**\n",
    "- 打印拟合得到的参数向量 `w`，即 `parameters[0]`。\n",
    "- 这些参数是通过最小二乘法优化得到的，表示使模型预测值与目标值最接近的参数。\n",
    "\n",
    "---\n",
    "\n",
    "### 示例流程\n",
    "假设：\n",
    "- `x` 是一个 `10x10` 的希尔伯特矩阵。\n",
    "- `y` 是通过 `y = np.dot(x, w)` 生成的目标值，其中 `w` 是真实的参数向量。\n",
    "\n",
    "代码的执行流程如下：\n",
    "1. 初始化参数向量 `p_init`，所有值为 `1`。\n",
    "2. 使用最小二乘法拟合参数，使得模型预测值 `np.dot(x, p)` 与目标值 `y` 的误差最小。\n",
    "3. 输出拟合得到的参数向量 `w`。\n",
    "\n",
    "---\n",
    "\n",
    "### 示例代码\n",
    "以下是一个完整的示例：\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "from scipy.linalg import hilbert\n",
    "from scipy.optimize import leastsq\n",
    "\n",
    "# 生成希尔伯特矩阵\n",
    "x = hilbert(10)\n",
    "\n",
    "# 随机生成真实参数 w\n",
    "np.random.seed(10)\n",
    "w_true = np.random.randint(2, 10, 10)\n",
    "\n",
    "# 计算目标值 y\n",
    "y = np.dot(x, w_true)\n",
    "\n",
    "# 定义模型和残差函数\n",
    "func = lambda p, x: np.dot(x, p)\n",
    "err_func = lambda p, x, y: func(p, x) - y\n",
    "\n",
    "# 初始化参数\n",
    "p_init = np.random.randint(1, 2, 10)\n",
    "\n",
    "# 最小二乘法拟合\n",
    "parameters = leastsq(err_func, p_init, args=(x, y))\n",
    "\n",
    "# 输出结果\n",
    "print(\"真实参数 w: \", w_true)\n",
    "print(\"拟合参数 w: \", parameters[0])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "\n",
    "---\n",
    "\n",
    "### 示例输出\n",
    "假设真实参数 `w_true` 是 `[9, 4, 5, 2, 9, 5, 9, 3, 7, 3]`，可能的输出为：\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": ""
    }
   },
   "outputs": [],
   "source": [
    "真实参数 w:  [9 4 5 2 9 5 9 3 7 3]\n",
    "拟合参数 w:  [9. 4. 5. 2. 9. 5. 9. 3. 7. 3.]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "\n",
    "---\n",
    "\n",
    "### 总结\n",
    "1. **代码功能**：\n",
    "   - 使用最小二乘法拟合线性模型的参数，使得模型预测值与目标值的误差最小。\n",
    "2. **关键点**：\n",
    "   - `func` 定义了线性模型公式。\n",
    "   - `err_func` 定义了残差函数。\n",
    "   - `leastsq` 通过优化残差函数拟合参数。\n",
    "3. **结果**：\n",
    "   - 输出拟合得到的参数向量 `w`，与真实参数 `w_true` 应该非常接近。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<style>#sk-container-id-1 {\n",
       "  /* Definition of color scheme common for light and dark mode */\n",
       "  --sklearn-color-text: #000;\n",
       "  --sklearn-color-text-muted: #666;\n",
       "  --sklearn-color-line: gray;\n",
       "  /* Definition of color scheme for unfitted estimators */\n",
       "  --sklearn-color-unfitted-level-0: #fff5e6;\n",
       "  --sklearn-color-unfitted-level-1: #f6e4d2;\n",
       "  --sklearn-color-unfitted-level-2: #ffe0b3;\n",
       "  --sklearn-color-unfitted-level-3: chocolate;\n",
       "  /* Definition of color scheme for fitted estimators */\n",
       "  --sklearn-color-fitted-level-0: #f0f8ff;\n",
       "  --sklearn-color-fitted-level-1: #d4ebff;\n",
       "  --sklearn-color-fitted-level-2: #b3dbfd;\n",
       "  --sklearn-color-fitted-level-3: cornflowerblue;\n",
       "\n",
       "  /* Specific color for light theme */\n",
       "  --sklearn-color-text-on-default-background: var(--sg-text-color, var(--theme-code-foreground, var(--jp-content-font-color1, black)));\n",
       "  --sklearn-color-background: var(--sg-background-color, var(--theme-background, var(--jp-layout-color0, white)));\n",
       "  --sklearn-color-border-box: var(--sg-text-color, var(--theme-code-foreground, var(--jp-content-font-color1, black)));\n",
       "  --sklearn-color-icon: #696969;\n",
       "\n",
       "  @media (prefers-color-scheme: dark) {\n",
       "    /* Redefinition of color scheme for dark theme */\n",
       "    --sklearn-color-text-on-default-background: var(--sg-text-color, var(--theme-code-foreground, var(--jp-content-font-color1, white)));\n",
       "    --sklearn-color-background: var(--sg-background-color, var(--theme-background, var(--jp-layout-color0, #111)));\n",
       "    --sklearn-color-border-box: var(--sg-text-color, var(--theme-code-foreground, var(--jp-content-font-color1, white)));\n",
       "    --sklearn-color-icon: #878787;\n",
       "  }\n",
       "}\n",
       "\n",
       "#sk-container-id-1 {\n",
       "  color: var(--sklearn-color-text);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 pre {\n",
       "  padding: 0;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 input.sk-hidden--visually {\n",
       "  border: 0;\n",
       "  clip: rect(1px 1px 1px 1px);\n",
       "  clip: rect(1px, 1px, 1px, 1px);\n",
       "  height: 1px;\n",
       "  margin: -1px;\n",
       "  overflow: hidden;\n",
       "  padding: 0;\n",
       "  position: absolute;\n",
       "  width: 1px;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-dashed-wrapped {\n",
       "  border: 1px dashed var(--sklearn-color-line);\n",
       "  margin: 0 0.4em 0.5em 0.4em;\n",
       "  box-sizing: border-box;\n",
       "  padding-bottom: 0.4em;\n",
       "  background-color: var(--sklearn-color-background);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-container {\n",
       "  /* jupyter's `normalize.less` sets `[hidden] { display: none; }`\n",
       "     but bootstrap.min.css set `[hidden] { display: none !important; }`\n",
       "     so we also need the `!important` here to be able to override the\n",
       "     default hidden behavior on the sphinx rendered scikit-learn.org.\n",
       "     See: https://github.com/scikit-learn/scikit-learn/issues/21755 */\n",
       "  display: inline-block !important;\n",
       "  position: relative;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-text-repr-fallback {\n",
       "  display: none;\n",
       "}\n",
       "\n",
       "div.sk-parallel-item,\n",
       "div.sk-serial,\n",
       "div.sk-item {\n",
       "  /* draw centered vertical line to link estimators */\n",
       "  background-image: linear-gradient(var(--sklearn-color-text-on-default-background), var(--sklearn-color-text-on-default-background));\n",
       "  background-size: 2px 100%;\n",
       "  background-repeat: no-repeat;\n",
       "  background-position: center center;\n",
       "}\n",
       "\n",
       "/* Parallel-specific style estimator block */\n",
       "\n",
       "#sk-container-id-1 div.sk-parallel-item::after {\n",
       "  content: \"\";\n",
       "  width: 100%;\n",
       "  border-bottom: 2px solid var(--sklearn-color-text-on-default-background);\n",
       "  flex-grow: 1;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-parallel {\n",
       "  display: flex;\n",
       "  align-items: stretch;\n",
       "  justify-content: center;\n",
       "  background-color: var(--sklearn-color-background);\n",
       "  position: relative;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-parallel-item {\n",
       "  display: flex;\n",
       "  flex-direction: column;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-parallel-item:first-child::after {\n",
       "  align-self: flex-end;\n",
       "  width: 50%;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-parallel-item:last-child::after {\n",
       "  align-self: flex-start;\n",
       "  width: 50%;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-parallel-item:only-child::after {\n",
       "  width: 0;\n",
       "}\n",
       "\n",
       "/* Serial-specific style estimator block */\n",
       "\n",
       "#sk-container-id-1 div.sk-serial {\n",
       "  display: flex;\n",
       "  flex-direction: column;\n",
       "  align-items: center;\n",
       "  background-color: var(--sklearn-color-background);\n",
       "  padding-right: 1em;\n",
       "  padding-left: 1em;\n",
       "}\n",
       "\n",
       "\n",
       "/* Toggleable style: style used for estimator/Pipeline/ColumnTransformer box that is\n",
       "clickable and can be expanded/collapsed.\n",
       "- Pipeline and ColumnTransformer use this feature and define the default style\n",
       "- Estimators will overwrite some part of the style using the `sk-estimator` class\n",
       "*/\n",
       "\n",
       "/* Pipeline and ColumnTransformer style (default) */\n",
       "\n",
       "#sk-container-id-1 div.sk-toggleable {\n",
       "  /* Default theme specific background. It is overwritten whether we have a\n",
       "  specific estimator or a Pipeline/ColumnTransformer */\n",
       "  background-color: var(--sklearn-color-background);\n",
       "}\n",
       "\n",
       "/* Toggleable label */\n",
       "#sk-container-id-1 label.sk-toggleable__label {\n",
       "  cursor: pointer;\n",
       "  display: flex;\n",
       "  width: 100%;\n",
       "  margin-bottom: 0;\n",
       "  padding: 0.5em;\n",
       "  box-sizing: border-box;\n",
       "  text-align: center;\n",
       "  align-items: start;\n",
       "  justify-content: space-between;\n",
       "  gap: 0.5em;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 label.sk-toggleable__label .caption {\n",
       "  font-size: 0.6rem;\n",
       "  font-weight: lighter;\n",
       "  color: var(--sklearn-color-text-muted);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 label.sk-toggleable__label-arrow:before {\n",
       "  /* Arrow on the left of the label */\n",
       "  content: \"▸\";\n",
       "  float: left;\n",
       "  margin-right: 0.25em;\n",
       "  color: var(--sklearn-color-icon);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 label.sk-toggleable__label-arrow:hover:before {\n",
       "  color: var(--sklearn-color-text);\n",
       "}\n",
       "\n",
       "/* Toggleable content - dropdown */\n",
       "\n",
       "#sk-container-id-1 div.sk-toggleable__content {\n",
       "  max-height: 0;\n",
       "  max-width: 0;\n",
       "  overflow: hidden;\n",
       "  text-align: left;\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-unfitted-level-0);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-toggleable__content.fitted {\n",
       "  /* fitted */\n",
       "  background-color: var(--sklearn-color-fitted-level-0);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-toggleable__content pre {\n",
       "  margin: 0.2em;\n",
       "  border-radius: 0.25em;\n",
       "  color: var(--sklearn-color-text);\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-unfitted-level-0);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-toggleable__content.fitted pre {\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-fitted-level-0);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 input.sk-toggleable__control:checked~div.sk-toggleable__content {\n",
       "  /* Expand drop-down */\n",
       "  max-height: 200px;\n",
       "  max-width: 100%;\n",
       "  overflow: auto;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 input.sk-toggleable__control:checked~label.sk-toggleable__label-arrow:before {\n",
       "  content: \"▾\";\n",
       "}\n",
       "\n",
       "/* Pipeline/ColumnTransformer-specific style */\n",
       "\n",
       "#sk-container-id-1 div.sk-label input.sk-toggleable__control:checked~label.sk-toggleable__label {\n",
       "  color: var(--sklearn-color-text);\n",
       "  background-color: var(--sklearn-color-unfitted-level-2);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-label.fitted input.sk-toggleable__control:checked~label.sk-toggleable__label {\n",
       "  background-color: var(--sklearn-color-fitted-level-2);\n",
       "}\n",
       "\n",
       "/* Estimator-specific style */\n",
       "\n",
       "/* Colorize estimator box */\n",
       "#sk-container-id-1 div.sk-estimator input.sk-toggleable__control:checked~label.sk-toggleable__label {\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-unfitted-level-2);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-estimator.fitted input.sk-toggleable__control:checked~label.sk-toggleable__label {\n",
       "  /* fitted */\n",
       "  background-color: var(--sklearn-color-fitted-level-2);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-label label.sk-toggleable__label,\n",
       "#sk-container-id-1 div.sk-label label {\n",
       "  /* The background is the default theme color */\n",
       "  color: var(--sklearn-color-text-on-default-background);\n",
       "}\n",
       "\n",
       "/* On hover, darken the color of the background */\n",
       "#sk-container-id-1 div.sk-label:hover label.sk-toggleable__label {\n",
       "  color: var(--sklearn-color-text);\n",
       "  background-color: var(--sklearn-color-unfitted-level-2);\n",
       "}\n",
       "\n",
       "/* Label box, darken color on hover, fitted */\n",
       "#sk-container-id-1 div.sk-label.fitted:hover label.sk-toggleable__label.fitted {\n",
       "  color: var(--sklearn-color-text);\n",
       "  background-color: var(--sklearn-color-fitted-level-2);\n",
       "}\n",
       "\n",
       "/* Estimator label */\n",
       "\n",
       "#sk-container-id-1 div.sk-label label {\n",
       "  font-family: monospace;\n",
       "  font-weight: bold;\n",
       "  display: inline-block;\n",
       "  line-height: 1.2em;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-label-container {\n",
       "  text-align: center;\n",
       "}\n",
       "\n",
       "/* Estimator-specific */\n",
       "#sk-container-id-1 div.sk-estimator {\n",
       "  font-family: monospace;\n",
       "  border: 1px dotted var(--sklearn-color-border-box);\n",
       "  border-radius: 0.25em;\n",
       "  box-sizing: border-box;\n",
       "  margin-bottom: 0.5em;\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-unfitted-level-0);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-estimator.fitted {\n",
       "  /* fitted */\n",
       "  background-color: var(--sklearn-color-fitted-level-0);\n",
       "}\n",
       "\n",
       "/* on hover */\n",
       "#sk-container-id-1 div.sk-estimator:hover {\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-unfitted-level-2);\n",
       "}\n",
       "\n",
       "#sk-container-id-1 div.sk-estimator.fitted:hover {\n",
       "  /* fitted */\n",
       "  background-color: var(--sklearn-color-fitted-level-2);\n",
       "}\n",
       "\n",
       "/* Specification for estimator info (e.g. \"i\" and \"?\") */\n",
       "\n",
       "/* Common style for \"i\" and \"?\" */\n",
       "\n",
       ".sk-estimator-doc-link,\n",
       "a:link.sk-estimator-doc-link,\n",
       "a:visited.sk-estimator-doc-link {\n",
       "  float: right;\n",
       "  font-size: smaller;\n",
       "  line-height: 1em;\n",
       "  font-family: monospace;\n",
       "  background-color: var(--sklearn-color-background);\n",
       "  border-radius: 1em;\n",
       "  height: 1em;\n",
       "  width: 1em;\n",
       "  text-decoration: none !important;\n",
       "  margin-left: 0.5em;\n",
       "  text-align: center;\n",
       "  /* unfitted */\n",
       "  border: var(--sklearn-color-unfitted-level-1) 1pt solid;\n",
       "  color: var(--sklearn-color-unfitted-level-1);\n",
       "}\n",
       "\n",
       ".sk-estimator-doc-link.fitted,\n",
       "a:link.sk-estimator-doc-link.fitted,\n",
       "a:visited.sk-estimator-doc-link.fitted {\n",
       "  /* fitted */\n",
       "  border: var(--sklearn-color-fitted-level-1) 1pt solid;\n",
       "  color: var(--sklearn-color-fitted-level-1);\n",
       "}\n",
       "\n",
       "/* On hover */\n",
       "div.sk-estimator:hover .sk-estimator-doc-link:hover,\n",
       ".sk-estimator-doc-link:hover,\n",
       "div.sk-label-container:hover .sk-estimator-doc-link:hover,\n",
       ".sk-estimator-doc-link:hover {\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-unfitted-level-3);\n",
       "  color: var(--sklearn-color-background);\n",
       "  text-decoration: none;\n",
       "}\n",
       "\n",
       "div.sk-estimator.fitted:hover .sk-estimator-doc-link.fitted:hover,\n",
       ".sk-estimator-doc-link.fitted:hover,\n",
       "div.sk-label-container:hover .sk-estimator-doc-link.fitted:hover,\n",
       ".sk-estimator-doc-link.fitted:hover {\n",
       "  /* fitted */\n",
       "  background-color: var(--sklearn-color-fitted-level-3);\n",
       "  color: var(--sklearn-color-background);\n",
       "  text-decoration: none;\n",
       "}\n",
       "\n",
       "/* Span, style for the box shown on hovering the info icon */\n",
       ".sk-estimator-doc-link span {\n",
       "  display: none;\n",
       "  z-index: 9999;\n",
       "  position: relative;\n",
       "  font-weight: normal;\n",
       "  right: .2ex;\n",
       "  padding: .5ex;\n",
       "  margin: .5ex;\n",
       "  width: min-content;\n",
       "  min-width: 20ex;\n",
       "  max-width: 50ex;\n",
       "  color: var(--sklearn-color-text);\n",
       "  box-shadow: 2pt 2pt 4pt #999;\n",
       "  /* unfitted */\n",
       "  background: var(--sklearn-color-unfitted-level-0);\n",
       "  border: .5pt solid var(--sklearn-color-unfitted-level-3);\n",
       "}\n",
       "\n",
       ".sk-estimator-doc-link.fitted span {\n",
       "  /* fitted */\n",
       "  background: var(--sklearn-color-fitted-level-0);\n",
       "  border: var(--sklearn-color-fitted-level-3);\n",
       "}\n",
       "\n",
       ".sk-estimator-doc-link:hover span {\n",
       "  display: block;\n",
       "}\n",
       "\n",
       "/* \"?\"-specific style due to the `<a>` HTML tag */\n",
       "\n",
       "#sk-container-id-1 a.estimator_doc_link {\n",
       "  float: right;\n",
       "  font-size: 1rem;\n",
       "  line-height: 1em;\n",
       "  font-family: monospace;\n",
       "  background-color: var(--sklearn-color-background);\n",
       "  border-radius: 1rem;\n",
       "  height: 1rem;\n",
       "  width: 1rem;\n",
       "  text-decoration: none;\n",
       "  /* unfitted */\n",
       "  color: var(--sklearn-color-unfitted-level-1);\n",
       "  border: var(--sklearn-color-unfitted-level-1) 1pt solid;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 a.estimator_doc_link.fitted {\n",
       "  /* fitted */\n",
       "  border: var(--sklearn-color-fitted-level-1) 1pt solid;\n",
       "  color: var(--sklearn-color-fitted-level-1);\n",
       "}\n",
       "\n",
       "/* On hover */\n",
       "#sk-container-id-1 a.estimator_doc_link:hover {\n",
       "  /* unfitted */\n",
       "  background-color: var(--sklearn-color-unfitted-level-3);\n",
       "  color: var(--sklearn-color-background);\n",
       "  text-decoration: none;\n",
       "}\n",
       "\n",
       "#sk-container-id-1 a.estimator_doc_link.fitted:hover {\n",
       "  /* fitted */\n",
       "  background-color: var(--sklearn-color-fitted-level-3);\n",
       "}\n",
       "</style><div id=\"sk-container-id-1\" class=\"sk-top-container\"><div class=\"sk-text-repr-fallback\"><pre>Ridge(fit_intercept=False)</pre><b>In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook. <br />On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.</b></div><div class=\"sk-container\" hidden><div class=\"sk-item\"><div class=\"sk-estimator fitted sk-toggleable\"><input class=\"sk-toggleable__control sk-hidden--visually\" id=\"sk-estimator-id-1\" type=\"checkbox\" checked><label for=\"sk-estimator-id-1\" class=\"sk-toggleable__label fitted sk-toggleable__label-arrow\"><div><div>Ridge</div></div><div><a class=\"sk-estimator-doc-link fitted\" rel=\"noreferrer\" target=\"_blank\" href=\"https://scikit-learn.org/1.6/modules/generated/sklearn.linear_model.Ridge.html\">?<span>Documentation for Ridge</span></a><span class=\"sk-estimator-doc-link fitted\">i<span>Fitted</span></span></div></label><div class=\"sk-toggleable__content fitted\"><pre>Ridge(fit_intercept=False)</pre></div> </div></div></div></div>"
      ],
      "text/plain": [
       "Ridge(fit_intercept=False)"
      ]
     },
     "execution_count": 31,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from sklearn.linear_model import Ridge\n",
    "\n",
    "ridge_model = Ridge(fit_intercept=False)  # 参数代表不增加截距项\n",
    "ridge_model.fit(x, y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([6.3497497 , 4.32792068, 3.40228975, 2.83692059, 2.44632895,\n",
       "       2.15683095, 1.93213214, 1.75189668, 1.60369747, 1.47944808])"
      ]
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ridge_model.coef_  # 打印模型参数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [],
   "source": [
    "\"\"\"不同 alpha 参数拟合\n",
    "\"\"\"\n",
    "alphas = np.linspace(1, 10, 20)\n",
    "\n",
    "coefs = []\n",
    "for a in alphas:\n",
    "    ridge = Ridge(alpha=a, fit_intercept=False)\n",
    "    ridge.fit(x, y)\n",
    "    coefs.append(ridge.coef_)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Text(0.5, 1.0, 'Ridge Regression')"
      ]
     },
     "execution_count": 34,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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5zdnFK4CEmA2rGwp92UQERFVNPapISIiIkdgqCEiIiJHYKghIiIiR2CoISIiIkdgqCEiIiJHYKghIiIiR2CoISIiIkdgqCEiIiJHYKghIiIiR2CoISIiIkdgqCEiIiJHYKghIiIiR2CoISIiIkdgqCEiIiJHYKghIiIiR2CoISIiIkdgqCEiIiJHYKghIiIiR2CoISIiIkeomFDz5JNP4oorrkBXVxdcLhceeuihguPvec971H77cskll5TteomIiKiyVEyoiUQiOPXUU3H33XdPeI6EmO7u7tzygx/8YE6vkYiIiCqXBxXi0ksvVctk/H4/Ojo65uyaiIiIqHpUTE3NdDz++ONoa2vD6tWr8f73vx8DAwPlviQiIiKqEBVTUzMVaXq66qqrsHz5cuzevRuf+MQnVM3OM888A7fbXfIxiURCLZZwODyHV0xERERzqWpCzTXXXJNbP/nkk3HKKadg5cqVqvbmwgsvLPmY2267DbfeeuscXiURERGVS1U1P9mtWLECra2t2LVr14TnfPzjH8fIyEhu2b9//5xeIxEREc2dqqmpKXbgwAHVp6azs3PSjsWyEBERkfNVTKgZGxsrqHXZs2cPtmzZgubmZrVIM9LVV1+tRj9Jn5qPfexjOO6443DxxReX9bqJiIioMlRMqNm0aRMuuOCC3PZNN92kyuuuuw733HMP/vjHP+I73/kOhoeH1QR9f/Znf4bPfe5zrIkhIiIixaXruo55QkY/NTQ0qP419fX15b4cIiIimsHP76rtKExERERkx1BDREREjsBQQ0RERI7AUENERESOwFBDREREjsBQQ0RERI7AUENERESOwFBDREREjsBQQ0RERI7AUENERESOwFBDREREjsBQQ0RERI7AUENERESOwFBDREREjsBQQ0RERI7AUENERESOwFBDREREjsBQQ0RERI7AUENERESOwFBDREREjsBQQ0RERI7AUENERESOwFBDREREjsBQQ0RERI7AUENERESOwFBDREREjsBQQ0RERI7AUENERESOwFBDREREjsBQQ0RERI7AUENERESOwFBDREREjsBQQ0RERI7AUENERESOwFBDREREjsBQQ0RERI7AUENERESOwFBDREREjsBQQ0RERI7AUENERESOwFBDREREjsBQQ0RERI7AUENERESOwFBDREREjsBQQ0RERI7AUENERESOwFBDREREjsBQQ0RERI7AUENERESOwFBDREREjsBQQ0RERI7AUENERESOwFBDREREjsBQQ0RERI7AUENERESOwFBDREREjsBQQ0RERI7AUENERESOwFBDREREjsBQQ0RERI7AUENERESOwFBDREREjlAxoebJJ5/EFVdcga6uLrhcLjz00EMFx3Vdx6c//Wl0dnYiGAzioosuws6dO8t2vURERFRZKibURCIRnHrqqbj77rtLHv/iF7+Iu+66C/feey+effZZ1NbW4uKLL0Y8Hp/zayUiIqLK40GFuPTSS9VSitTS3Hnnnfi///f/4q1vfava95//+Z9ob29XNTrXXHPNHF8tERERVZqKqamZzJ49e9DT06OanCwNDQ04++yz8cwzz5T12oiIiKgyVExNzWQk0AipmbGTbetYKYlEQi2WcDg8i1dJRERE5VQVNTVH67bbblM1OtayePHicl8SERERzedQ09HRocre3t6C/bJtHSvl4x//OEZGRnLL/v37Z/1aiYiIqDyqItQsX75chZdHH320oClJRkFt2LBhwsf5/X7U19cXLERERORMFdOnZmxsDLt27SroHLxlyxY0NzdjyZIl+PCHP4zPf/7zWLVqlQo5n/rUp9ScNldeeWVZr5uIiIgqQ8WEmk2bNuGCCy7Ibd90002qvO666/Dtb38bH/vYx9RcNn/7t3+L4eFhnHfeeXjkkUcQCATKeNVERERUKVy6TAIzT0iTlXQYlv41bIoiIiJy1ud3VfSpISIiIpoKQw0RERE5AkMNEREROQJDDRERETkCQw0RERE5AkMNEREROQJDDRERETkCQw0RERE5AkMNEREROQJDDRERETkCQw0RERE5AkMNEREROQJDDRERETkCQw0RERE5AkMNEREROQJDDRERETkCQw0RERE5gqfcF0AzJ5PV8Yc9g+gbjaOtLoCzljfDrbnKfVlERERzgqHGIR7Z2o1bH96G7pF4bl9nQwC3XHEiLlnbWdZrIyIimgtsfnJIoHn//ZsLAo3oGYmr/XKciIjI6RhqHNDkJDU0eolj1j45LucRERE5GUNNlZM+NMU1NHYSZeS4nEdERORkDDVVTjoFz+R5RERE1YqhpsrJKKeZPI+IiKhaMdRUORm2LaOcJhq4LfvluJxHRETkZAw1VU7moZFh26I42Fjbcpzz1RARkdMx1DiA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",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "\"\"\"绘制不同 alpha 参数结果\n",
    "\"\"\"\n",
    "from matplotlib import pyplot as plt\n",
    "\n",
    "%matplotlib inline\n",
    "\n",
    "plt.plot(alphas, coefs)  # 绘制不同 alpha 参数下的 w 拟合值\n",
    "plt.scatter(np.linspace(1, 0, 10), parameters[0])  # 普通最小二乘法拟合的 w 值放入图中\n",
    "plt.xlabel(\"alpha\")\n",
    "plt.ylabel(\"w\")\n",
    "plt.title(\"Ridge Regression\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Text(0.5, 1.0, 'Lasso Regression')"
      ]
     },
     "execution_count": 35,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "\"\"\"使用 LASSO 回归拟合并绘图\n",
    "\"\"\"\n",
    "from sklearn.linear_model import Lasso\n",
    "\n",
    "alphas = np.linspace(1, 10, 10)\n",
    "lasso_coefs = []\n",
    "\n",
    "for a in alphas:\n",
    "    lasso = Lasso(alpha=a, fit_intercept=False)\n",
    "    lasso.fit(x, y)\n",
    "    lasso_coefs.append(lasso.coef_)\n",
    "\n",
    "plt.plot(alphas, lasso_coefs)  # 绘制不同 alpha 参数下的 w 拟合值\n",
    "plt.scatter(np.linspace(1, 0, 10), parameters[0])  # 普通最小二乘法拟合的 w 值放入图中\n",
    "plt.xlabel(\"alpha\")\n",
    "plt.ylabel(\"w\")\n",
    "plt.title(\"Lasso Regression\")"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": ".venv",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
